#include "string.h"
#include "mailbox.h"

#define MAX_NUM_BOX 32

  mailbox_t mboxs[MAX_NUM_BOX];
  mutex_lock_t alloc_lock;

static int mbox_is_full(mailbox_t *mailbox)
{
   
}

static int mbox_is_empty(mailbox_t *mailbox)
{
    
}

static void init_mbox(mailbox_t *mailbox)
{
    
}

void mbox_init()
{
    int i;
    do_mutex_lock_init(&alloc_lock);
    for(i = 0;i < MAX_NUM_BOX;i ++)
    {
        mboxs[i].used=0;
        mboxs[i].visit=0;
        mboxs[i].front=0;
        mboxs[i].rear=0;
        mboxs[i].id = i;
        do_condition_init(&mboxs[i].full);
        do_condition_init(&mboxs[i].empty);
        do_mutex_lock_init(&mboxs[i].mutex);
        mboxs[i].name[0]='\0';
    }
}

int do_mbox_open(char *name)
{
    int j = -1;
    do_mutex_lock_acquire(&alloc_lock);
    int i;
    for(i = 0; i < MAX_NUM_BOX; i++)
    {
        if(mboxs[i].name[0] == '\0' && j < 0)
        {
            j = i;
            mboxs[i].visit = 1;
        }
        else if(!strcmp(mboxs[i].name, name))
        {
            j = i;
            mboxs[i].visit++;
            break;
        }
    }
    if(mboxs[j].name[0] == '\0')
        strcpy(mboxs[j].name, name);
    do_mutex_lock_release(&alloc_lock);
    return mboxs[j].id;
}

void do_mbox_close(int mboxid)
{
    mailbox_t *mailbox = &mboxs[mboxid];
    do_mutex_lock_acquire(&alloc_lock);
    if(mailbox->visit <= 1)
    {
        mailbox->name[0] = '\0';
        mailbox->front = mailbox->rear = 0;
        mailbox->used = 0;
        mailbox->visit = 0;
        do_condition_init(&mailbox->full);
        do_condition_init(&mailbox->empty);
        do_mutex_lock_init(&mailbox->mutex);
    }
    do_mutex_lock_release(&alloc_lock);
}

void do_mbox_send(int mboxid, void *msg, int msg_length)
{
    mailbox_t *mailbox = &mboxs[mboxid];
    do_mutex_lock_acquire(&mailbox->mutex);
    while(msg_length > MAX_MBOX_LENGTH - mailbox->used )
        do_condition_wait(&mailbox->mutex, &mailbox->empty);
    if(msg_length > MAX_MBOX_LENGTH - mailbox->rear)
    {
        int first_write =  MAX_MBOX_LENGTH - mailbox->rear;
        memcpy((char *)(mailbox->buffer + mailbox->rear), (char *)msg, first_write);
        memcpy((char *)mailbox->buffer, (char *)(msg + first_write), msg_length - first_write);
        mailbox->rear = msg_length - first_write;
    }
    else
    {
        memcpy((char *)(mailbox->buffer + mailbox->rear), (char *)msg, msg_length);
        mailbox->rear += msg_length;
    }

    mailbox->used += msg_length;
    do_condition_broadcast(&mailbox->full);
    do_mutex_lock_release(&mailbox->mutex);
}

void do_mbox_recv(int mboxid, void *msg, int msg_length)
{
    mailbox_t *mailbox = &mboxs[mboxid];
    do_mutex_lock_acquire(&mailbox->mutex);
    while(mailbox->used < msg_length)
    {
        do_condition_wait(&mailbox->mutex, &mailbox->full);
    }
    if(MAX_MBOX_LENGTH - mailbox->front < msg_length)
    {
        int first_read = MAX_MBOX_LENGTH - mailbox->front;
        memcpy((char *)msg, (char *)(mailbox->buffer + mailbox->front), first_read);
        memcpy((char *)(msg + first_read), (char *)mailbox->buffer, msg_length - first_read);
        mailbox->front = msg_length - first_read;
    }
    else
    {
        memcpy((char *)msg, (char *)(mailbox->buffer + mailbox->front), msg_length);
        mailbox->front += msg_length;
    }
    mailbox->used -= msg_length;
    do_condition_broadcast(&mailbox->empty);
    do_mutex_lock_release(&mailbox->mutex);
}